#include "examples.h"
void Examples::TestPolyMult()
{
    cout<<"   TestPolyMult..."<<endl;
    // 对于函数 f(x) = x^3 + 2x^2 + x + 3 , 计算x = {1,2,3,4,5}的结果并验证
    // 1. 设置安全参数
    long logN = 13;
    long lambda = 128;
    int dNum = 3;

    // 2.初始化参数相关内容
    Context context = Context::InitContext(logN, lambda);
    // Context context = Context::InitContext(logN, lambda, dNum);

    // 3.计算私钥
    SecretKey secretKey(context);

    // 4.初始化同态操作相关内容
    Scheme scheme(secretKey, context);
    long slots = context.Nh;
    uint64_t *mvec = new uint64_t[slots];
    uint64_t *mvecPoly = new uint64_t[slots];
    uint64_t *mvecPlain = new uint64_t[slots];
    for (long i = 0; i < 5; i++) {
        mvec[i] = i + 1;
        mvecPlain[i] = 3;
    }
    for (int i = 5; i < slots; ++i) {
        mvec[i] = 0; // 设置为 0 + 0i
        mvecPlain[i] = 0;
    }

    // 6.计算多项式运算结果
    for (long i = 0; i < 5; i++) {
        mvecPoly[i] = static_cast<uint64_t>(pow(mvec[i], 3) + 2 * pow(mvec[i], 2) + mvec[i] + 3);
    }
    cout<<endl;

    // 7.计算同态运算结果
    Ciphertext cipher = scheme.Encrypt(mvec, slots, context.L);
    Ciphertext multCipher2 = Ciphertext(context.N, slots, context.L);
    Ciphertext multCipher3 = Ciphertext(context.N, slots, context.L);
    
    scheme.Mult(multCipher2, cipher, cipher);
    scheme.Mult(multCipher3, multCipher2, cipher); 
    scheme.MultConstAndEqual(multCipher2, 2);
    scheme.AddAndEqual(cipher, multCipher2);
    scheme.AddAndEqual(cipher, multCipher3);
    Plaintext plain = scheme.Encode(mvecPlain, slots, context.L);
    scheme.AddPt(cipher, cipher, plain);

    // 8.将同态运算结果与正确值进行对比
    uint64_t *dvecMul = scheme.Decrypt(secretKey, cipher);
    StringUtils::ShowCompare(mvecPoly, dvecMul, 5, "PolyMult");
}


void Examples::TestRotate()
{
    cout<<"   TestRotate..."<<endl;
    // 设置满槽消息 , 进行同态旋转并验证结果
    // 1. 设置安全参数
    long logN = 15;
    long lambda = 128;
    int dNum = 0;

    // 2.初始化参数相关内容
    // Context context = Context::InitContext(logN, lambda);
    Context context = Context::InitContext(logN, lambda, dNum);

    // 3.计算私钥
    SecretKey secretKey(context);

    // 4.设置旋转索引
    int rotSlots = 3;

    // 5.初始化同态操作相关内容
    Scheme scheme(secretKey, context);
    scheme.AddLeftRotKey(secretKey, rotSlots);
    

    // 6.设置消息值
    long slots = context.Nh;
    uint64_t *mvec = new uint64_t[slots];
    for (int i = 0; i < slots; i++) {
        mvec[i] = i;
    }

    // 7.加密消息值
    Ciphertext cipher = scheme.Encrypt(mvec, slots, context.L);
    
    // 8.进行同态旋转操作并解密结果
    scheme.LeftRotateAndEqual(cipher, rotSlots);
    uint64_t *dvec = scheme.Decrypt(secretKey, cipher);

    // 9.对消息值进行旋转并与解密结果对比
    EvaluatorUtils::LeftRotateAndEqual(mvec, slots, rotSlots);
    StringUtils::ShowCompare(mvec, dvec, 5, "rot");
    
}